package com.liulishuo.filedownloader;

import android.util.Log;

import com.liulishuo.filedownloader.model.FileDownloadStatus;
import com.waterstudio.filedownloader.ext.m3u8.M3u8DownloadCallback;
import com.waterstudio.filedownloader.ext.m3u8.M3u8FileDownloader;
import com.waterstudio.filedownloader.ext.m3u8.R;


/**
 * Created by chensuilun on 2019/3/11.
 */
public class M3u8DownloadListenerWrapper extends FileDownloadLargeFileListener {
    private static final String TAG = "M3u8DownloadListenerWra";
    private
    FileDownloadLargeFileListener mProxyListener;
    /**
     * M3U8 文件下载的初始 TASK，后续的 TS 文件下载都会使用该原始 TASK 作为回调
     */
    private M3U8DownloadTask mOriginM3u8Task;

    private M3u8DownloadCallback mDownloadCallback;


    M3u8DownloadListenerWrapper(FileDownloadLargeFileListener proxyListener, M3u8DownloadCallback callback) {
        mProxyListener = proxyListener;
        mDownloadCallback = callback;
    }

    public byte getStatus() {
        return mOriginM3u8Task.getGroupStatus();
    }

    @Override
    protected boolean isInvalid() {
        return mIsDestroy;
    }

    @Override
    protected void pending(BaseDownloadTask task, long soFarBytes, long totalBytes) {
        if (M3u8FileDownloader.getInstance().isM3u8TsTask(task)) {
            if (com.waterstudio.filedownloader.ext.m3u8.BuildConfig.LOG_ENABLE) {
                Log.v(TAG, String.format("ts %d pending", M3u8FileDownloader.getInstance().getTsIndex(task)));
            }
            mDownloadCallback.onUpdateProgress(mOriginM3u8Task, task, soFarBytes, totalBytes);
        } else if (M3u8FileDownloader.getInstance().isM3u8Task(task)) {
            mOriginM3u8Task = (M3U8DownloadTask) task;
            if (!mDownloadCallback.onPendingDownloadM3u8(task, this)) {
                destroy();
                //already download
                if (task.getTag(R.id.ts_merge_path) instanceof String) {
                    mOriginM3u8Task.setGroupStatus(FileDownloadStatus.completed);
                    mProxyListener.completed(mOriginM3u8Task);
                } else {
                    //otherwise ts task is downloading
                    warn(task);
                }
            } else {
                mOriginM3u8Task.setGroupStatus(FileDownloadStatus.pending);
                mProxyListener.pending(task, 0L, 100L);
            }
        } else {
            mProxyListener.pending(task, soFarBytes, totalBytes);
        }
    }


    @Override
    protected void started(BaseDownloadTask task) {
        if (M3u8FileDownloader.getInstance().isM3u8TsTask(task)) {
            if (com.waterstudio.filedownloader.ext.m3u8.BuildConfig.LOG_ENABLE) {
                Log.v(TAG, String.format("ts %d started", M3u8FileDownloader.getInstance().getTsIndex(task)));
            }
            return;
        } else if (M3u8FileDownloader.getInstance().isM3u8Task(task)) {
            mOriginM3u8Task.setGroupStatus(FileDownloadStatus.started);
        }
        mProxyListener.started(task);
    }

    @Override
    protected void connected(BaseDownloadTask task, String etag, boolean isContinue, long soFarBytes, long totalBytes) {
        if (M3u8FileDownloader.getInstance().isM3u8TsTask(task)) {
            if (com.waterstudio.filedownloader.ext.m3u8.BuildConfig.LOG_ENABLE) {
                Log.v(TAG, String.format("ts %d connected", M3u8FileDownloader.getInstance().getTsIndex(task)));
            }
        } else if (M3u8FileDownloader.getInstance().isM3u8Task(task)) {
            mOriginM3u8Task.setGroupStatus(FileDownloadStatus.connected);
            mProxyListener.pending(task, 0, 100L);
        } else {
            mProxyListener.connected(task, etag, isContinue, soFarBytes, totalBytes);
        }
    }


    @Override
    protected void progress(BaseDownloadTask task, long soFarBytes, long totalBytes) {
        if (M3u8FileDownloader.getInstance().isM3u8Task(task)) {
            mOriginM3u8Task.setGroupStatus(FileDownloadStatus.progress);
            mProxyListener.progress(mOriginM3u8Task, 0, 100L);
        } else if (M3u8FileDownloader.getInstance().isM3u8TsTask(task)) {
            mOriginM3u8Task.setGroupStatus(FileDownloadStatus.progress);
            int progress = (int) (mDownloadCallback.onUpdateProgress(mOriginM3u8Task, task, soFarBytes, totalBytes) * 100L);
            //1% is the merge part.
            mProxyListener.progress(mOriginM3u8Task, Math.min(99, progress), 100L);
        } else {
            mProxyListener.progress(task, soFarBytes, totalBytes);
        }
    }


    @Override
    protected void blockComplete(BaseDownloadTask task) throws Throwable {
        if (M3u8FileDownloader.getInstance().isM3u8Task(task)) {
            //M3u8 task
            mOriginM3u8Task = (M3U8DownloadTask) task;
            if (!mDownloadCallback.onInterceptBlockCompleteM3u8(task, this)) {
                //already download
                if (task.getTag(R.id.ts_merge_path) instanceof String) {
                    mOriginM3u8Task.setGroupStatus(FileDownloadStatus.blockComplete);
                    mProxyListener.blockComplete(mOriginM3u8Task);
                } else {
                    //otherwise ts task is downloading,do not call warn callback directly on non-UI thread, call warn on the complete callback
                    mOriginM3u8Task.setGroupStatus(FileDownloadStatus.warn);
                }
            } else {
                mOriginM3u8Task.setGroupStatus(FileDownloadStatus.progress);
                mProxyListener.blockComplete(mOriginM3u8Task);
            }
        } else if (M3u8FileDownloader.getInstance().isM3u8TsTask(task)) {
            //ts task
            if (mDownloadCallback.onBlockCompleteTs(mOriginM3u8Task, task)) {
                mOriginM3u8Task.setGroupStatus(FileDownloadStatus.blockComplete);
                mProxyListener.blockComplete(mOriginM3u8Task);
            }
        } else {
            if (mProxyListener != null) {
                mProxyListener.blockComplete(task);
            }
        }
    }

    @Override
    protected void retry(BaseDownloadTask task, Throwable ex, int retryingTimes, long soFarBytes) {
        if (M3u8FileDownloader.getInstance().isM3u8TsTask(task)) {
            if (com.waterstudio.filedownloader.ext.m3u8.BuildConfig.LOG_ENABLE) {
                Log.w(TAG, String.format("ts %d retry,url %s", M3u8FileDownloader.getInstance().getTsIndex(task), task.getUrl()));
            }
        } else if (mProxyListener != null) {
            mProxyListener.retry(task, ex, retryingTimes, soFarBytes);
        }
    }


    @Override
    protected void completed(BaseDownloadTask task) {
        if (M3u8FileDownloader.getInstance().isM3u8Task(task)) {
            if (getStatus() == FileDownloadStatus.warn) {
                //ts task is downloading, end.
                destroy();
                mProxyListener.warn(mOriginM3u8Task);
                return;
            }
            if (!mDownloadCallback.onInterceptCompleteM3u8(task)) {
                //m3u8 task already downloaded, end.
                destroy();
                mOriginM3u8Task.setGroupStatus(FileDownloadStatus.completed);
                mProxyListener.completed(mOriginM3u8Task);
            }
        } else if (M3u8FileDownloader.getInstance().isM3u8TsTask(task)) {
            if (mDownloadCallback.onCompleteTs(mOriginM3u8Task, task)) {
                destroy();
                mOriginM3u8Task.setGroupStatus(FileDownloadStatus.completed);
                mProxyListener.completed(mOriginM3u8Task);
            }
        } else {
            mProxyListener.completed(task);
        }
    }

    @Override
    protected void paused(BaseDownloadTask task, long soFarBytes, long totalBytes) {

        destroy();
        if (M3u8FileDownloader.getInstance().isM3u8TsTask(task)) {
            //ts 暂停的触发就是对整个 listener 的暂停，所以接收到回调即可认为全部 ts 已经暂停了，不需要再次暂停
            if (com.waterstudio.filedownloader.ext.m3u8.BuildConfig.LOG_ENABLE) {
                Log.w(TAG, String.format("ts %d paused,url %s", M3u8FileDownloader.getInstance().getTsIndex(task), task.getUrl()));
            }
            if (getStatus() != FileDownloadStatus.error) {
                //不是因为其中一个 ts 下载失败导致的暂停
                mOriginM3u8Task.setGroupStatus(FileDownloadStatus.paused);
                int progress = (int) (mDownloadCallback.onUpdateProgress(mOriginM3u8Task, task, soFarBytes, totalBytes) * 100);
                mDownloadCallback.onTsDownloadPaused(mOriginM3u8Task, task);
                mProxyListener.paused(mOriginM3u8Task, Math.min(99, progress), 100L);
            }
        } else if (M3u8FileDownloader.getInstance().isM3u8Task(task)) {
            mOriginM3u8Task.setGroupStatus(FileDownloadStatus.paused);
            mProxyListener.paused(task, 0, 0L);
        } else {
            mOriginM3u8Task.setGroupStatus(FileDownloadStatus.paused);
            mProxyListener.paused(task, soFarBytes, totalBytes);

        }
    }

    @Override
    protected void error(BaseDownloadTask task, Throwable e) {
        destroy();
        if (M3u8FileDownloader.getInstance().isM3u8TsTask(task)) {
            if (com.waterstudio.filedownloader.ext.m3u8.BuildConfig.LOG_ENABLE) {
                Log.w(TAG, String.format("ts %d error,url %s", M3u8FileDownloader.getInstance().getTsIndex(task), task.getUrl()), e);
            }
            mOriginM3u8Task.setGroupStatus(FileDownloadStatus.error);
            mDownloadCallback.onTsDownloadError(mOriginM3u8Task, task);
            mProxyListener.error(mOriginM3u8Task, e);
        } else {
            mOriginM3u8Task.setGroupStatus(FileDownloadStatus.error);
            mProxyListener.error(task, e);
        }
    }

    @Override
    protected void warn(BaseDownloadTask task) {
        if (M3u8FileDownloader.getInstance().isM3u8TsTask(task)) {
            return;
        }
        destroy();
        mOriginM3u8Task.setGroupStatus(FileDownloadStatus.warn);
        if (mProxyListener != null) {
            mProxyListener.warn(task);
        }
    }

    private boolean mIsDestroy;

    private void destroy() {
        if (com.waterstudio.filedownloader.ext.m3u8.BuildConfig.LOG_ENABLE) {
            Log.i(TAG, "destroy", new Throwable());
        }
        mIsDestroy = true;
    }

}
